"""
PDF基站数据提取器 - 面向对象封装版

功能：提取PDF文件中的基站监测数据并保存到Excel
特点：
- 面向对象封装，维护内部状态更安全
- 完整类型提示，提高代码可读性和IDE支持
- 模块化设计，各页面处理逻辑独立
- 增强的错误处理和边界检查
"""

import pdfplumber
import re
import os
import pandas as pd
from pathlib import Path
from typing import Optional, Dict, List, Any


class PDFStationAnalyzer:
    """PDF基站数据提取分析器"""
    def __init__(self, pdf_dir: str, excel_path: str):
        """
        初始化PDF基站分析器
        
        :param pdf_dir: PDF文件所在目录
        :param excel_path: 结果Excel文件路径
        """
        self.pdf_dir = pdf_dir
        self.excel_path = excel_path
        # 预定义结果结构，避免键错误
        self.result_structure: Dict[str, Optional[str]] = {
            "监测对象": None,
            "使用开始时间": None,
            "使用结束时间": None,
            "仪器名称": None,
            "仪器型号": None,
            "仪器出厂编号": None,
            "报告编号": None,
            "主检人": None
        }

    def _clean_text(self, text: Optional[str]) -> str:
        """清理文本中的换行符和多余空格"""
        if not text:
            return ""
        # 替换各种换行符为空格，然后合并多余空格
        return " ".join(str(text).replace("\n", "").replace("\r", "").split())

    def _extract_time_range(self, text: str) -> Optional[Dict[str, str]]:
        """从文本中提取时间范围"""
        monitoring_time_match = re.search(
            r"监测时间[:：]\s*([^\n]+(?:\n[^\n]+)*?)\s*(?:通信基站信息|监测方法)",
            text,
            re.DOTALL,
        )
        if not monitoring_time_match:
            return None

        monitoring_time_text = self._clean_text(monitoring_time_match.group(1))
        time_pattern = r"(\d{4}-\d{2}-\d{2} \d{2}:\d{2})至(\d{4}-\d{2}-\d{2} \d{2}:\d{2})"
        time_match = re.search(time_pattern, monitoring_time_text)
        if time_match:
            return {
                "start_time": time_match.group(1),
                "end_time": time_match.group(2)
            }
        return None

    def _extract_first_page(self, page) -> Dict[str, Optional[str]]:
        """提取第一页信息"""
        result = {}
        page_text = page.extract_text()
        if not page_text:
            return result

        # 使用正则表达式提取报告编号和监测对象
        pattern = r"第(\d+)号\n(.*?)\n项目名称："
        project_name_match = re.search(pattern, page_text, re.DOTALL)
        if project_name_match:
            result["报告编号"] = self._clean_text(project_name_match.group(1))
            result["监测对象"] = self._clean_text(project_name_match.group(2))

        return result

    def _extract_fourth_page(self, page) -> Dict[str, Optional[str]]:
        """提取第四页信息"""
        result = {}
        page_text = page.extract_text()
        if not page_text:
            return result

        # 提取主检人信息
        pattern = r"监测人\n(.*?)\n"
        project_name_match = re.search(pattern, page_text, re.DOTALL)
        if project_name_match:
            result["主检人"] = self._clean_text(project_name_match.group(1))

        return result

    def _extract_third_page(self, page) -> Dict[str, Optional[str]]:
        """提取第三页信息"""
        result = {}
        page_text = page.extract_text()
        if not page_text:
            return result

        # 提取时间范围
        time_range = self._extract_time_range(page_text)
        if time_range:
            result["使用开始时间"] = time_range["start_time"]
            result["使用结束时间"] = time_range["end_time"]

        # 提取仪器信息 - 使用表格提取功能
        tables = page.extract_tables()
        if tables:
            for table in tables:
                if len(table) > 1 and any("仪器名称" in str(cell) for cell in table[0]):
                    headers = [self._clean_text(cell) for cell in table[0]]
                    data = table[1] if len(table) > 1 else []
                    # pdf表格头对应result键
                    header_mapping = {
                        "仪器名称": "仪器名称",
                        "仪器型号": "仪器型号",
                        "仪器编号": "仪器出厂编号",
                    }

                    for i, header in enumerate(headers):
                        if header in header_mapping and i < len(data):
                            result[header_mapping[header]] = self._clean_text(data[i])

        # 如果表格提取失败，使用正则表达式作为后备方案
        if not result.get("仪器名称"):
            instrument_info_match = re.search(
                r"仪器名称\s*仪器型号\s*仪器编号\s*([^\n]+)\s+([^\n]+)\s+([^\n]+)",
                page_text,
            )
            if instrument_info_match:
                result["仪器名称"] = self._clean_text(instrument_info_match.group(1))
                result["仪器型号"] = self._clean_text(instrument_info_match.group(2))
                result["仪器出厂编号"] = self._clean_text(instrument_info_match.group(3))

        return result

    def _process_pdf_file(self, pdf_path: str) -> Dict[str, Optional[str]]:
        """处理单个PDF文件并提取数据"""
        # 初始化结果字典
        result = self.result_structure.copy()

        with pdfplumber.open(pdf_path) as pdf:
            # 检查页面是否存在
            if len(pdf.pages) < 5:
                return result

            # 提取第一页信息
            first_page_data = self._extract_first_page(pdf.pages[0])
            result.update(first_page_data)

            # 提取第四页数据
            fourth_page_data = self._extract_fourth_page(pdf.pages[4])
            result.update(fourth_page_data)

            # 提取第三页数据
            third_page_data = self._extract_third_page(pdf.pages[2])
            result.update(third_page_data)

        return result

    def _append_to_excel(self, data: List[Dict[str, Optional[str]]]):
        """将数据追加到Excel文件"""
        # 创建新数据的DataFrame
        new_df = pd.DataFrame(data)

        # 检查文件是否存在
        if os.path.exists(self.excel_path):
            # 读取现有数据
            existing_df = pd.read_excel(self.excel_path)
            # 追加新数据
            combined_df = pd.concat([existing_df, new_df], ignore_index=True)
        else:
            # 如果文件不存在，直接使用新数据
            combined_df = new_df

        # 写入Excel文件
        combined_df.to_excel(self.excel_path, index=False)

    def extract_data(self) -> List[Dict[str, Optional[str]]]:
        """提取所有PDF文件数据并保存到Excel"""
        all_extracted_data = []

        # 遍历pdf目录下的所有PDF文件
        for root, _, files in os.walk(self.pdf_dir):
            for file in files:
                if file.lower().endswith(".pdf"):
                    pdf_path = os.path.join(root, file)
                    # 解析PDF文件
                    extracted_data = self._process_pdf_file(pdf_path)
                    all_extracted_data.append(extracted_data)

                    # 重命名文件
                    if extracted_data.get("报告编号") and extracted_data.get("监测对象"):
                        new_filename = os.path.join(
                            self.pdf_dir,
                            f"{extracted_data['报告编号']}-{extracted_data['监测对象']}.pdf",
                        )
                        os.rename(pdf_path, new_filename)
                        print(f"已将 {pdf_path} 重命名为 {new_filename}")

        # 将所有数据写入Excel
        if all_extracted_data:
            self._append_to_excel(all_extracted_data)

        return all_extracted_data


def main():
    # 获取pdf目录路径
    pdf_dir = os.path.join(os.path.dirname(__file__), "pdf")
    excel_file = os.path.join(
        os.path.dirname(__file__), "template", "仪器设备使用记录.xlsx"
    )

    # 创建分析器实例并提取数据
    analyzer = PDFStationAnalyzer(pdf_dir, excel_file)
    analyzer.extract_data()


if __name__ == "__main__":
    main()
